<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<title>Load visualizations via a webmap</title>
<style>
  html,
  body,
  #viewDiv {
    padding: 0;
    margin: 0;
    height: 100%;
    width: 100%;
  }
</style>

<link rel="stylesheet" href="https://js.arcgis.com/4.3/esri/css/main.css">
<script src="https://js.arcgis.com/4.3/"></script>

<script>
  require([
    "esri/WebMap",
    "esri/views/MapView",
    "esri/widgets/Legend",
    "esri/widgets/LayerList",
    "dojo/domReady!"
  ], function(WebMap, MapView, Legend, LayerList) {

    var map = new WebMap({
      portalItem: {
        id: "8bcfd58b039a4477a0eb734fe6c8d4fe"
      }
    });

    var view = new MapView({
      container: "viewDiv"
    });

    var rendererInfos;

    map.load().then(function(){
      rendererInfos = map.layers.map(function(layer){
        return {
          renderer: layer.renderer.clone(),
          title: layer.title
        };
      });
      rendererInfos.reverse();
      var visibleLayer = map.layers.find(function(layer){
        layer.title = map.portalItem.title;
        return layer.visible;
      });
      map.layers.removeAll();
      map.layers.add(visibleLayer);
      view.map = map;
      return view;
    }).then(addWidgets);

    function addWidgets(view){
      var layerList = new LayerList({
        view: view,
        createActionsFunction: createLayerListActions
      });
      var legend = new Legend({
        view: view
      });
      view.ui.add(layerList, "top-right");
      view.ui.add(legend, "bottom-left");

      layerList.on("trigger-action", fireAction);
    }

    function createLayerListActions(evt){
      if(evt.item.title = map.portalItem.title){
        evt.item.actionsOpen = true;
        return rendererInfos.map(function(rendererInfo){
          var actions = [];

          actions.push({
            title: rendererInfo.title,
            className: "esri-icon-maps",
            id: "change-renderer",
            rendererTitle: rendererInfo.title
          });

          var renderer = rendererInfo.renderer;
          var hasOpacityVV = renderer && renderer.visualVariables.some(function(variable){
            return variable.type === "opacity";
          });

          if (hasOpacityVV){
            actions.push({
              title: "Toggle opacity",
              className: "esri-icon-environment-settings",
              id: "toggle-opacity",
              rendererTitle: rendererInfo.title
            });
          }
          return actions;
        }).toArray();

      }
    }

    function fireAction(evt){
      var actionId = evt.action.id;
      var actionTitle = evt.action.title;

      if (evt.action.id === "change-renderer"){
        toggleRenderer(actionTitle);
      } else if (evt.action.id === "toggle-opacity"){
        toggleOpacity(evt.action.rendererTitle);
      } else {
        console.log("Couldn't find a matching action.");
      }

    }

    function toggleOpacity(title){

      var layer = view.map.layers.getItemAt(0);
      var matchingRendererInfo = rendererInfos.find(function(info){
        return info.title === layerRendererTitle && info.title === title;
      });

      if(!matchingRendererInfo){
        return;
      }

      var renderer = layer.renderer.clone();

      if (hasOpacityVV(renderer)){
        var opacityIndex;
        // findIndex isn't IE compatable
        renderer.visualVariables.forEach(function(variable, index){
          if (variable.type === "opacity"){
            opacityIndex = index;
          }
        });
        renderer.visualVariables.splice(opacityIndex,1);
      } else {
        renderer = matchingRendererInfo.renderer;
      }

      layer.renderer = renderer;
    }

    function hasOpacityVV (renderer){
      return renderer && renderer.visualVariables.some(function(variable){
        return variable.type === "opacity";
      });
    }

    var layerRendererTitle;

    function toggleRenderer(title){
      var matchingInfo = rendererInfos.find(function(info){
        return info.title === title;
      });
      var renderer = matchingInfo.renderer.clone();
      var layer = view.map.layers.getItemAt(0);
      layer.renderer = renderer;
      layerRendererTitle = matchingInfo.title;
    }

  });
</script>
</head>

<body>
  <div id="viewDiv"></div>
</body>
</html>